﻿using System;

namespace StatePattern;

public abstract class LiftState
{
    //声明环境角色类变量
    public Context? Context { set; get; }

    //电梯开启操作
    public abstract void Open();

    //电梯关闭操作
    public abstract void Close();

    //电梯运行操作
    public abstract void Run();

    //电梯停止操作
    public abstract void Stop();
}

public class OpeningState : LiftState
{
    //当前状态要执行的方法
    public override void Open()
    {
        Console.WriteLine("电梯门开启");
    }

    public override void Close()
    {
        //修改状态
        Context?.SetLiftState(Context.ClosingState);
        //调用当前状态中的context中的close方法
        Context?.Close();
    }

    public override void Run()
    {
        Console.WriteLine("电梯门开启，不能运行");
    }

    public override void Stop()
    {
        Console.WriteLine("电梯门开启，则电梯已经停止，无需停止");
    }
}

public class RunningState : LiftState
{
    //运行的时候开电梯门？你疯了！电梯不会给你开的
    public override void Open()
    {
        Console.WriteLine("电梯运行时，电梯门不能开启");
    }

    //电梯门关闭？这是肯定了
    public override void Close()
    {
        //虽然可以关门，但这个动作不归我执行
        //do nothing
    }

    //这是在运行状态下要实现的方法
    public override void Run()
    {
        Console.WriteLine("电梯正在运行...");
    }

    //这个事绝对是合理的，光运行不停止还有谁敢做这个电梯？！估计只有上帝了
    public override void Stop()
    {
        Context?.SetLiftState(Context.StoppingState);
        Context?.Stop();
    }
}

public class StoppingState : LiftState
{
    //停止状态，开门，那是要的！
    public override void Open()
    {
        //状态修改
        Context?.SetLiftState(Context.OpeningState);
        //动作委托为CloseState来执行，也就是委托给了ClosingState子类执行这个动作
        Context?.GetLiftState().Open();
    }

    public override void Close()
    {
        //虽然可以关门，但这个动作不归我执行
        //状态修改
        Context?.SetLiftState(Context.ClosingState);
        //动作委托为CloseState来执行，也就是委托给了ClosingState子类执行这个动作
        Context?.GetLiftState().Close();
    }

    //停止状态再跑起来，正常的很
    public override void Run()
    {
        //状态修改
        Context?.SetLiftState(Context.RunningState);
        //动作委托为CloseState来执行，也就是委托给了ClosingState子类执行这个动作
        Context?.GetLiftState().Run();
    }

    //停止状态是怎么发生的呢？当然是停止方法执行了
    public override void Stop()
    {
        Console.WriteLine("电梯停止了...");
    }
}

public class ClosingState : LiftState
{
    //电梯门关闭，这是关闭状态要实现的动作
    public override void Close()
    {
        Console.WriteLine("电梯门关闭...");
    }

    //电梯门关了再打开，逗你玩呢，那这个允许呀
    public override void Open()
    {
        Context?.SetLiftState(Context.OpeningState);
        Context?.Open();
    }


    //电梯门关了就跑，这是再正常不过了
    public override void Run()
    {
        Context?.SetLiftState(Context.RunningState);
        Context?.Run();
    }

    //电梯门关着，我就不按楼层
    public override void Stop()
    {
        Context?.SetLiftState(Context.StoppingState);
        Context?.Stop();
    }
}

public class Context
{
    //定义对应状态对象的常量
    public static readonly OpeningState OpeningState = new();
    public static readonly ClosingState ClosingState = new();
    public static readonly RunningState RunningState = new();
    public static readonly StoppingState StoppingState = new();

    //定义一个当前电梯状态变量
    private LiftState _liftState;

    public LiftState GetLiftState()
    {
        return _liftState;
    }

    //设置当前状态对象
    public void SetLiftState(LiftState liftState)
    {
        _liftState = liftState;
        //设置当前状态对象中的Context对象
        _liftState.Context = this;
    }

    public void Open()
    {
        _liftState.Open();
    }

    public void Close()
    {
        _liftState.Close();
    }

    public void Run()
    {
        _liftState.Run();
    }

    public void Stop()
    {
        _liftState.Stop();
    }
}

public static class Program
{
    public static void Main()
    {
        //创建环境角色对象
        var context = new Context();
        //设置当前电梯装填
        context.SetLiftState(new ClosingState());//设置一个默认的状态：关闭状态

        context.Open();//打开门
        //context.Close();//关闭门，如果注释这行代码，那么电梯就无法运行了
        context.Run();
        context.Close();//已经关闭了，所以什么都不做
        context.Stop();
        context.Open();
    }
}